<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <meta name="google-site-verification" content="_hgg1Y3vl6FDA0y9ycG3MRMdmBljtivpN0MGPBl9Vks">
  <meta name="baidu-site-verification" content="code-BjkBUVTz39">

<link rel="stylesheet" href="/css/main.css">

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Noto Serif SC:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext">
<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"wangduwei.top","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":true,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":"gitalk | valine","storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

<script data-ad-client="ca-pub-8087648226243491" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

  <meta name="description" content="一、概述你可能对 Iterable 和 Sequence 傻傻分不清。看一下他们的代码： 1234567interface Iterable&lt;out T&gt; &amp;#123;    operator fun iterator(): Iterator&lt;T&gt;&amp;#125;interface Sequence&lt;out T&gt; &amp;#123;    operator fun ite">
<meta property="og:type" content="article">
<meta property="og:title" content="高效Kotlin-51：使用Sequence优化集合操作">
<meta property="og:url" content="https://wangduwei.top/kotlin-lang-sequence.html">
<meta property="og:site_name" content="嗅不到北的狗子">
<meta property="og:description" content="一、概述你可能对 Iterable 和 Sequence 傻傻分不清。看一下他们的代码： 1234567interface Iterable&lt;out T&gt; &amp;#123;    operator fun iterator(): Iterator&lt;T&gt;&amp;#125;interface Sequence&lt;out T&gt; &amp;#123;    operator fun ite">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://wangduwei.top/images/kotlin_sequence_operation.jpeg">
<meta property="og:image" content="https://wangduwei.top/images/kotlin_sequence_order.jpeg">
<meta property="og:image" content="https://wangduwei.top/images/kotlin_sequence_min_op.jpeg">
<meta property="og:image" content="https://wangduwei.top/images/kotlin_sequence_debug.jpeg">
<meta property="article:published_time" content="2021-11-06T13:37:43.000Z">
<meta property="article:modified_time" content="2021-11-06T14:47:39.655Z">
<meta property="article:author" content="wangduwei">
<meta property="article:tag" content="Kotlin">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://wangduwei.top/images/kotlin_sequence_operation.jpeg">

<link rel="canonical" href="https://wangduwei.top/kotlin-lang-sequence.html">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>高效Kotlin-51：使用Sequence优化集合操作 | 嗅不到北的狗子</title>
  
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-69Z1P1CBTV"></script>
    <script>
      if (CONFIG.hostname === location.hostname) {
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', 'G-69Z1P1CBTV');
      }
    </script>


  <script>
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?9f3c7bb2232e1e3fda4c019e4a4406c0";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="嗅不到北的狗子" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">嗅不到北的狗子</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-sitemap">

    <a href="/sitemap.xml" rel="section"><i class="fa fa-sitemap fa-fw"></i>站点地图</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://wangduwei.top/kotlin-lang-sequence.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpeg">
      <meta itemprop="name" content="wangduwei">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="嗅不到北的狗子">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          高效Kotlin-51：使用Sequence优化集合操作
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2021-11-06 21:37:43 / 修改时间：22:47:39" itemprop="dateCreated datePublished" datetime="2021-11-06T21:37:43+08:00">2021-11-06</time>
            </span>

          
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/kotlin-lang-sequence.html#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/kotlin-lang-sequence.html" itemprop="commentCount"></span>
    </a>
  </span>
  
  <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>7.9k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>7 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h4 id="一、概述"><a href="#一、概述" class="headerlink" title="一、概述"></a>一、概述</h4><p>你可能对 <code>Iterable</code> 和 <code>Sequence</code> 傻傻分不清。看一下他们的代码：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Iterable</span>&lt;<span class="type">out T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">iterator</span><span class="params">()</span></span>: Iterator&lt;T&gt;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Sequence</span>&lt;<span class="type">out T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">iterator</span><span class="params">()</span></span>: Iterator&lt;T&gt;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p>好像只有名字不一样-_-||，但他们却有着本质的区别。<code>Sequence</code>属于懒加载，中间操作符不会触发计算，仅仅是对前一个Sequence的装饰，只有在遇到toList()或count()这些终止操作符时才会执行真正的计算工作。而Iterable每一步都返回一个新的集合。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">inline</span> <span class="function"><span class="keyword">fun</span> <span class="type">&lt;T&gt;</span> Iterable<span class="type">&lt;T&gt;</span>.<span class="title">filter</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">    predicate: (<span class="type">T</span>) -&gt; <span class="type">Boolean</span></span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>: List&lt;T&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> filterTo(ArrayList&lt;T&gt;(), predicate)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">fun</span> <span class="type">&lt;T&gt;</span> Sequence<span class="type">&lt;T&gt;</span>.<span class="title">filter</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">    predicate: (<span class="type">T</span>) -&gt; <span class="type">Boolean</span></span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>: Sequence&lt;T&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> FilteringSequence(<span class="keyword">this</span>, <span class="literal">true</span>, predicate)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下图中filter操作符不做任何计算操作，只是返回一个装饰器对象，在遇到toList()操作符才执行计算。</p>
<center>
    <img src="../images/kotlin_sequence_operation.jpeg" width="500"/>
</center>

<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">val</span> seq = sequenceOf(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line"><span class="keyword">val</span> filtered = seq.filter &#123; print(<span class="string">&quot;f<span class="variable">$it</span> &quot;</span>); it % <span class="number">2</span> == <span class="number">1</span> &#125;</span><br><span class="line">println(filtered)  <span class="comment">// FilteringSequence@...</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">val</span> asList = filtered.toList()</span><br><span class="line"><span class="comment">// f1 f2 f3</span></span><br><span class="line">println(asList) <span class="comment">// [1, 3]</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">val</span> list = listOf(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line"><span class="keyword">val</span> listFiltered = list</span><br><span class="line">    .filter &#123; print(<span class="string">&quot;f<span class="variable">$it</span> &quot;</span>); it % <span class="number">2</span> == <span class="number">1</span> &#125;</span><br><span class="line"><span class="comment">// f1 f2 f3</span></span><br><span class="line">println(listFiltered) <span class="comment">// [1, 3]</span></span><br></pre></td></tr></table></figure>

<h4 id="二、优势"><a href="#二、优势" class="headerlink" title="二、优势"></a>二、优势</h4><p>Sequence的惰性执行有以下几个优点：</p>
<ul>
<li>保证操作的顺序性</li>
<li>保证操作执行次数最少化</li>
<li>他们可以是无限的</li>
<li>无需每一步创建新的集合</li>
</ul>
<p>下面依次讨论一下这些优点</p>
<h5 id="一、顺序性很重要"><a href="#一、顺序性很重要" class="headerlink" title="一、顺序性很重要"></a>一、顺序性很重要</h5><table>
    <tr>
        <td>使用Sequence处理数据时，每个元素依次执行所有操作符。这是一种元素接元素的处理方式。</td>
        <td>使用Iterable处理数据时，每个操作符依次执行所有数据。这是一种步骤接步骤的处理方式。</td>
    </tr>
     <tr>
            <td>
            <figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">sequenceOf(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line">    .filter &#123; </span><br><span class="line">        print(<span class="string">&quot;F<span class="variable">$it</span>, &quot;</span>); </span><br><span class="line">        it % <span class="number">2</span> == <span class="number">1</span> </span><br><span class="line">    &#125;</span><br><span class="line">    .map &#123; </span><br><span class="line">        print(<span class="string">&quot;M<span class="variable">$it</span>, &quot;</span>); </span><br><span class="line">        it * <span class="number">2</span> </span><br><span class="line">    &#125;</span><br><span class="line">    .forEach &#123; </span><br><span class="line">        print(<span class="string">&quot;E<span class="variable">$it</span>, &quot;</span>) </span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// Prints: F1, M1, E2, F2, F3, M3, E6, </span></span><br></pre></td></tr></table></figure>
            </td>
            <td>
            <figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">listOf(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line">    .filter &#123; </span><br><span class="line">        print(<span class="string">&quot;F<span class="variable">$it</span>, &quot;</span>); </span><br><span class="line">        it % <span class="number">2</span> == <span class="number">1</span> </span><br><span class="line">    &#125;</span><br><span class="line">    .map &#123; </span><br><span class="line">        print(<span class="string">&quot;M<span class="variable">$it</span>, &quot;</span>); </span><br><span class="line">        it * <span class="number">2</span> </span><br><span class="line">    &#125;</span><br><span class="line">    .forEach &#123; </span><br><span class="line">        print(<span class="string">&quot;E<span class="variable">$it</span>, &quot;</span>) </span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// Prints: F1, F2, F3, M1, M3, E2, E6,</span></span><br></pre></td></tr></table></figure>
            </td>
        </tr>
</table>


<center>
    <img src="../images/kotlin_sequence_order.jpeg" width="500"/>
</center>

<p>如果我们不用集合处理函数，而是用循环和条件语句，这和sequence一样，也是一种元素接元素的处理方式。这也为我们提供了一种编译器底层优化的思路：sequence操作可以被优化成循环和条件。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (e <span class="keyword">in</span> listOf(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)) &#123;</span><br><span class="line">    print(<span class="string">&quot;F<span class="variable">$e</span>, &quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> (e % <span class="number">2</span> == <span class="number">1</span>) &#123;</span><br><span class="line">        print(<span class="string">&quot;M<span class="variable">$e</span>, &quot;</span>)</span><br><span class="line">        <span class="keyword">val</span> mapped = e * <span class="number">2</span></span><br><span class="line">        print(<span class="string">&quot;E<span class="variable">$mapped</span>, &quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// Prints: F1, M1, E2, F2, F3, M3, E6,</span></span><br></pre></td></tr></table></figure>


<h5 id="二、Sequence执行最少的操作"><a href="#二、Sequence执行最少的操作" class="headerlink" title="二、Sequence执行最少的操作"></a>二、Sequence执行最少的操作</h5><p>我们没必要每一步都处理整个集合。假如我们有一百万个数据，我们只需要前十个，没必要处理十个之后的数据。所以sequence可以执行最少的操作。</p>
<center>
    <img src="../images/kotlin_sequence_min_op.jpeg" width="500"/>
</center>

<p>看下面的例子：</p>
<table>
     <tr>
            <td>
            <figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">(<span class="number">1.</span><span class="number">.10</span>).asSequence()</span><br><span class="line">    .filter &#123; </span><br><span class="line">        print(<span class="string">&quot;F<span class="variable">$it</span>, &quot;</span>); </span><br><span class="line">        it % <span class="number">2</span> == <span class="number">1</span> </span><br><span class="line">    &#125;</span><br><span class="line">    .map &#123; </span><br><span class="line">        print(<span class="string">&quot;M<span class="variable">$it</span>, &quot;</span>); </span><br><span class="line">        it * <span class="number">2</span> </span><br><span class="line">    &#125;</span><br><span class="line">    .find &#123; </span><br><span class="line">        it &gt; <span class="number">5</span> </span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// Prints: F1, M1, F2, F3, M3,</span></span><br></pre></td></tr></table></figure>
            </td>
            <td>
            <figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">(<span class="number">1.</span><span class="number">.10</span>)</span><br><span class="line">    .filter &#123; </span><br><span class="line">        print(<span class="string">&quot;F<span class="variable">$it</span>, &quot;</span>); </span><br><span class="line">        it % <span class="number">2</span> == <span class="number">1</span> </span><br><span class="line">    &#125;</span><br><span class="line">    .map &#123; </span><br><span class="line">        print(<span class="string">&quot;M<span class="variable">$it</span>, &quot;</span>); </span><br><span class="line">        it * <span class="number">2</span> </span><br><span class="line">    &#125;</span><br><span class="line">    .find &#123; </span><br><span class="line">        it &gt; <span class="number">5</span> </span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// Prints: </span></span><br><span class="line"><span class="comment">//F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, </span></span><br><span class="line"><span class="comment">// M1, M3, M5, M7, M9,         </span></span><br></pre></td></tr></table></figure>
            </td>
        </tr>
</table>

<p>这个例子中，有很多个操作符，最后的终止操作符不需要处理所有的数据，因此sequence性能更好。类似的操作符还有：<code>first</code>, <code>find</code>, <code>take</code>, <code>any</code>, <code>all</code>, <code>none</code> 或 <code>indexOf</code>。</p>
<h5 id="三、Sequence是无限的"><a href="#三、Sequence是无限的" class="headerlink" title="三、Sequence是无限的"></a>三、Sequence是无限的</h5><p>由于Sequence按需处理，我们可以定义无限序列。一种常用的方式是使用sequence生成器 <code>generateSequence</code> 或 <code>sequence</code> 。</p>
<p><code>generateSequence</code>需要传如第一个值，以及如何产生下一个值：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">generateSequence(<span class="number">1</span>) &#123; it + <span class="number">1</span> &#125;</span><br><span class="line">    .map &#123; it * <span class="number">2</span> &#125;</span><br><span class="line">    .take(<span class="number">10</span>)</span><br><span class="line">    .forEach &#123; print(<span class="string">&quot;<span class="variable">$it</span>, &quot;</span>) &#125;</span><br><span class="line"><span class="comment">// Prints: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20,</span></span><br></pre></td></tr></table></figure>

<p><code>sequence</code> 则使用挂起函数按需生成数据。只要我们需要数据他就执行，一直到调用yield方法。然后挂起直到下次再向他请求数据。下面是一个无限生成斐波那契数列的例子：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.math.BigDecimal</span><br><span class="line"></span><br><span class="line"><span class="keyword">val</span> fibonacci: Sequence&lt;BigDecimal&gt; = sequence &#123;</span><br><span class="line">    <span class="keyword">var</span> current = <span class="number">1.</span>toBigDecimal()</span><br><span class="line">    <span class="keyword">var</span> prev = <span class="number">1.</span>toBigDecimal()</span><br><span class="line">    yield(prev)</span><br><span class="line">    <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">        yield(current)</span><br><span class="line">        <span class="keyword">val</span> temp = prev</span><br><span class="line">        prev = current</span><br><span class="line">        current += temp</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    print(fibonacci.take(<span class="number">10</span>).toList())</span><br><span class="line">    <span class="comment">// [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>需要注意的是，使用无限序列需要限制元素的数量，否则将无限的运行下去。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">print(fibonacci.toList()) <span class="comment">// Runs forever</span></span><br></pre></td></tr></table></figure>

<p>为了不让它无限循环的运行，我们可以使用<code>take</code>限制元素数量，或者使用first、find、indexOf等。在不限制数量的情况下，不要使用any、all、none。</p>
<h5 id="四、sequence每一步不产生新集合"><a href="#四、sequence每一步不产生新集合" class="headerlink" title="四、sequence每一步不产生新集合"></a>四、sequence每一步不产生新集合</h5><p>标准的集合处理函数每一步都返回新的集合，当我们处理大量数据时会分配很多临时内存。</p>
<table>
     <tr>
         <td>
            <figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">num</span><br><span class="line">   .filter &#123;<span class="comment">// 1                   </span></span><br><span class="line">       it % <span class="number">10</span> == <span class="number">0</span> </span><br><span class="line">   &#125; </span><br><span class="line">   .map &#123;<span class="comment">// 2      </span></span><br><span class="line">       it * <span class="number">2</span> </span><br><span class="line">   &#125; </span><br><span class="line">   .sum()</span><br><span class="line"><span class="comment">// In total, 2 collections </span></span><br><span class="line"><span class="comment">// created under the hood</span></span><br></pre></td></tr></table></figure>
         </td>
         <td>
            <figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">num.asSequence()</span><br><span class="line">   .filter &#123;<span class="comment">//0 </span></span><br><span class="line">      it % <span class="number">10</span> == <span class="number">0</span> </span><br><span class="line">   &#125;</span><br><span class="line">   .map &#123;<span class="comment">//0</span></span><br><span class="line">      it * <span class="number">2</span> </span><br><span class="line">   &#125;</span><br><span class="line">   .sum()</span><br><span class="line"><span class="comment">// No collections created</span></span><br></pre></td></tr></table></figure>
         </td>
     </tr>
</table>

<p>一个极端又常见的例子：文件读取。文件可能是几个G，每执行一个操作符都分配这么多内存是一种极大的浪费。下面例子是读取大小1.53G的芝加哥犯罪记录中包含毒品交易信息的记录数量，其中readLines 返回 List<String>。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// BAD SOLUTION, DO NOT USE COLLECTIONS FOR </span></span><br><span class="line"><span class="comment">// POSSIBLY BIG FILES</span></span><br><span class="line">File(<span class="string">&quot;ChicagoCrimes.csv&quot;</span>)</span><br><span class="line">    .readLines()</span><br><span class="line">    .drop(<span class="number">1</span>) <span class="comment">// Drop descriptions of the columns</span></span><br><span class="line">    .mapNotNull &#123; it.split(<span class="string">&quot;,&quot;</span>).getOrNull(<span class="number">6</span>) &#125;</span><br><span class="line">    <span class="comment">// Find description</span></span><br><span class="line">    .filter &#123; <span class="string">&quot;CANNABIS&quot;</span> <span class="keyword">in</span> it &#125;</span><br><span class="line">    .count()</span><br><span class="line">    .let(::println)</span><br></pre></td></tr></table></figure>
<p>这段程序在我电脑上的运行结果是：</p>
<figure class="highlight shell"><figcaption><span>script</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">OutOfMemoryError.n&gt; Exception in thread &quot;main&quot; java.lang.OutOfMemoryError: Java heap space</span><br></pre></td></tr></table></figure>

<p>我们创建了一个集合，中间三个操作符产生集合，一个四个集合。其中三个包含文件的主要主要数据记录，一共消耗4.59G。正确的实现应该使用sequence，我们使用<code>useLines</code>函数，每次只操作一行记录。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">File(<span class="string">&quot;ChicagoCrimes.csv&quot;</span>).useLines &#123; lines -&gt;</span><br><span class="line"><span class="comment">// The type of `lines` is Sequence&lt;String&gt;</span></span><br><span class="line">    lines.drop(<span class="number">1</span>) <span class="comment">// Drop descriptions of the columns</span></span><br><span class="line">        .mapNotNull &#123; it.split(<span class="string">&quot;,&quot;</span>).getOrNull(<span class="number">6</span>) &#125;</span><br><span class="line">        <span class="comment">// Find description</span></span><br><span class="line">        .filter &#123; <span class="string">&quot;CANNABIS&quot;</span> <span class="keyword">in</span> it &#125;</span><br><span class="line">        .count()</span><br><span class="line">        .let &#123; println(it) &#125; <span class="comment">// 318185</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>同样运行这段代码，只耗时8.3s。为了比较一下这两种方法的效率，我做了另外一个实验：删除数据中不必要的列以减少文件大小，得到<code>CrimeData.csv</code>只有728MB，然后做相同的操作。使用Collection处理函数，耗时13s，使用sequence函数，耗时4.5s。正如实验数据，使用sequence处理大文件不仅节约内存，而且提升性能。</p>
<p>事实上，在每个步骤中，我们创建一个新的集合本身也是一种成本，当我们处理包含大量元素的集合时，这种成本就会显现出来。差别并不大——主要是因为在许多步骤中创建的集合都是用预期的大小初始化的，所以当我们添加元素时，我们只需要将它们放在下一个位置。尽管即使是廉价的集合复制也比完全不复制要昂贵，这也是为什么我们应该更喜欢对具有<em>多个处理步骤</em>的<em>大集合</em>使用Sequence的主要原因。</p>
<blockquote>
<p>大集合：元素多（含数万个元素的整数列表）、元素大（超长字符串）</p>
<p>多个处理步骤：处理集合时使用很多操作符。</p>
</blockquote>
<p>如果对比下面两个函数：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fun</span> <span class="title">singleStepListProcessing</span><span class="params">()</span></span>: List&lt;Product&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> productsList.filter &#123; it.bought &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fun</span> <span class="title">singleStepSequenceProcessing</span><span class="params">()</span></span>: List&lt;Product&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> productsList.asSequence()</span><br><span class="line">        .filter &#123; it.bought &#125;</span><br><span class="line">        .toList()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>你会发现，在性能上区别不大（实际上，简单的list处理更快，因为它的filter函数是内联的）。但是，当你使用多个操作符，先filter再map，在大集合上性能问题就行显现出来。为了看到区别，我们比较一下2个操作符和3个操作符处理5000个数据的情况：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fun</span> <span class="title">twoStepListProcessing</span><span class="params">()</span></span>: List&lt;<span class="built_in">Double</span>&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> productsList</span><br><span class="line">        .filter &#123; it.bought &#125;</span><br><span class="line">        .map &#123; it.price &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fun</span> <span class="title">twoStepSequenceProcessing</span><span class="params">()</span></span>: List&lt;<span class="built_in">Double</span>&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> productsList.asSequence()</span><br><span class="line">        .filter &#123; it.bought &#125;</span><br><span class="line">        .map &#123; it.price &#125;</span><br><span class="line">        .toList()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fun</span> <span class="title">threeStepListProcessing</span><span class="params">()</span></span>: <span class="built_in">Double</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> productsList</span><br><span class="line">        .filter &#123; it.bought &#125;</span><br><span class="line">        .map &#123; it.price &#125;</span><br><span class="line">        .average()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fun</span> <span class="title">threeStepSequenceProcessing</span><span class="params">()</span></span>: <span class="built_in">Double</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> productsList.asSequence()</span><br><span class="line">        .filter &#123; it.bought &#125;</span><br><span class="line">        .map &#123; it.price &#125;</span><br><span class="line">        .average()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下面是在MacBook Pro(Retina, 15-inch, Late 2013)处理5000个元素的平均结果：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">twoStepListProcessing                        81 095 ns</span><br><span class="line">twoStepSequenceProcessing                    55 685 ns</span><br><span class="line">twoStepListProcessingAndAcumulate            83 307 ns</span><br><span class="line">twoStepSequenceProcessingAndAcumulate         6 928 ns</span><br></pre></td></tr></table></figure>

<p>很难预测我们能提升但是性能，根据我的观察，在一个包含多个步骤的典型集合处理中，对于至少几千个元素，我们可以预期大约20-40%的性能提升。</p>
<h5 id="五、sequence什么时候没那么快？"><a href="#五、sequence什么时候没那么快？" class="headerlink" title="五、sequence什么时候没那么快？"></a>五、sequence什么时候没那么快？</h5><p>有些情况我们要处理整个集合，sequence并不能给我们带来什么收益。如<code>sorted</code>（当前来讲它是唯一一个例子）。sorted的最优实现：积攒Sequence并放入List，然后使用Java的sort函数。缺点是，与<code>Collection.sort</code>相比，积攒过程会消耗额外的时间。</p>
<p>Sequence是否应该支持<code>sorted</code>函数是有争议的，因为当一个序列的方法需要所有元素才能完成计算时，后续操作只是部分延迟，并且它不支持无限序列。之所以添加sorted操作只是因为它很常用，好用。Kotlin开发者需要了解它的缺陷，尤其是它不能用于无限序列。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">generateSequence(<span class="number">0</span>) &#123; it + <span class="number">1</span> &#125;.take(<span class="number">10</span>).sorted().toList()</span><br><span class="line"><span class="comment">// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]</span></span><br><span class="line">generateSequence(<span class="number">0</span>) &#123; it + <span class="number">1</span> &#125;.sorted().take(<span class="number">10</span>).toList()</span><br><span class="line"><span class="comment">// Infinite time. Does not return.</span></span><br></pre></td></tr></table></figure>

<p>在Collection上使用sorted比在Sequence上更快只是少数特例。当我们只使用很少操作符函数和单个sorted函数时，还是建议使用sequence来处理。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">productsList.asSequence()</span><br><span class="line">    .filter &#123; it.bought &#125;</span><br><span class="line">    .map &#123; it.price &#125;</span><br><span class="line">    .sorted()</span><br><span class="line">    .take(<span class="number">10</span>)</span><br><span class="line">    .sum()</span><br></pre></td></tr></table></figure>

<h5 id="六、看看Java的Stream操作"><a href="#六、看看Java的Stream操作" class="headerlink" title="六、看看Java的Stream操作"></a>六、看看Java的Stream操作</h5><p>Java 8新增了集合处理流的特性，看起来和Kotlin的序列很像。</p>
<table>
     <tr>
         <td>
            <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">productsList.asSequence()</span><br><span class="line">    .filter &#123; it.bought &#125;</span><br><span class="line">    .map &#123; it.price &#125;</span><br><span class="line">    .average()</span><br></pre></td></tr></table></figure>
         </td>
         <td>
            <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">productsList.stream()</span><br><span class="line">    .filter &#123; it.bought &#125;</span><br><span class="line">    .mapToDouble &#123; it.price &#125;</span><br><span class="line">    .average()</span><br><span class="line">    .orElse(<span class="number">0.0</span>)</span><br></pre></td></tr></table></figure>
         </td>
     </tr>
</table>

<p>Java 8的Stream也是惰性的在最后一个操作符触发计算。与Kotlin sequence的区别主要是：</p>
<ul>
<li>Kotlin sequence包含更多的处理函数（被定义为拓展函数），使用简单: <code>toList()</code> vs <code>collect(Collectors.toList())</code></li>
<li>Java stream可以开启并行模式，在多核处理器上会有很大的性能提升。</li>
<li>Kotlin sequence可以用于Kotlin/JVM、Kotlin/JS、Kotlin/Native模块中。Java stream只能用于Kotlin/JVM，且JVM版本至少是8</li>
</ul>
<p>总之，我们不用Java stream并行模式时很难将谁的性能更好，我建议少用Java stream，只有在处理重量级计算问题中使用并行模式可以显著带来收益的情况下使用，其他情况用Kotlin标准函数能带来清晰的代码结构和多平台支持。</p>
<h5 id="七、调试Sequence"><a href="#七、调试Sequence" class="headerlink" title="七、调试Sequence"></a>七、调试Sequence</h5><p>Kotlin Sequence和Java Stream都支持debug每一步操作。Java需要使用”Java Stream Debugger”插件，Kotlin则需要”Kotlin Sequence Debugger”插件，现在已经被集成在了Kotlin插件中了。</p>
<center>
    <img src="../images/kotlin_sequence_debug.jpeg" width="500"/>
</center>


<h4 id="三、总结"><a href="#三、总结" class="headerlink" title="三、总结"></a>三、总结</h4><p>集合和序列非常相似，都支持相同的处理函数。但他们也有很大的区别。Sequence处理是困难的，因为我们要保持原集合不变，执行相应转换后再放回原集合。Sequence是惰性的，带来很多优点：</p>
<ul>
<li>保证操作的顺序性</li>
<li>保证操作执行次数最少化</li>
<li>他们可以是无限的</li>
<li>无需每一步创建新的集合</li>
</ul>
<p>基于这些优点，对于包含多个处理步骤的包含大对象或元素很多的集合来说使用Sequence更好。Sequence也包含调试器，能帮助我们可视化的分析元素处理过程。Sequence不是为了取代传统的集合处理方式，使用前应该分析清楚自己的目的和原因才能带来性能的提升以及更少的内存问题。</p>

    </div>

    
    
    
        <div class="reward-container">
  <div>赏你一杯咖啡</div>
  <button onclick="var qr = document.getElementById('qr'); qr.style.display = (qr.style.display === 'none') ? 'block' : 'none';">
    打赏
  </button>
  <div id="qr" style="display: none;">
      
      <div style="display: inline-block;">
        <img src="/images/wechatpay.png" alt="wangduwei 微信支付">
        <p>微信支付</p>
      </div>
      
      <div style="display: inline-block;">
        <img src="/images/alipay.jpeg" alt="wangduwei 支付宝">
        <p>支付宝</p>
      </div>

  </div>
</div>

        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>wangduwei
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://wangduwei.top/kotlin-lang-sequence.html" title="高效Kotlin-51：使用Sequence优化集合操作">https://wangduwei.top/kotlin-lang-sequence.html</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/Kotlin/" rel="tag"># Kotlin</a>
          </div>

        
  <div class="post-widgets">
    <div class="wp_rating">
      <div id="wpac-rating"></div>
    </div>
  </div>


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/kotlin-coroutine-deep-recursion.html" rel="prev" title="用Kotlin协程解决深度递归问题">
      <i class="fa fa-chevron-left"></i> 用Kotlin协程解决深度递归问题
    </a></div>
      <div class="post-nav-item"></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          
      <div class="tabs tabs-comment">
        <ul class="nav-tabs">
            <li class="tab"><a href="#comment-gitalk">gitalk</a></li>
            <li class="tab"><a href="#comment-valine">valine</a></li>
        </ul>
        <div class="tab-content">
            <div class="tab-pane gitalk" id="comment-gitalk">
              <div class="comments" id="gitalk-container"></div>
            </div>
            <div class="tab-pane valine" id="comment-valine">
              <div class="comments" id="valine-comments"></div>
            </div>
        </div>
      </div>

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E6%A6%82%E8%BF%B0"><span class="nav-number">1.</span> <span class="nav-text">一、概述</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E4%BC%98%E5%8A%BF"><span class="nav-number">2.</span> <span class="nav-text">二、优势</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E9%A1%BA%E5%BA%8F%E6%80%A7%E5%BE%88%E9%87%8D%E8%A6%81"><span class="nav-number">2.1.</span> <span class="nav-text">一、顺序性很重要</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E4%BA%8C%E3%80%81Sequence%E6%89%A7%E8%A1%8C%E6%9C%80%E5%B0%91%E7%9A%84%E6%93%8D%E4%BD%9C"><span class="nav-number">2.2.</span> <span class="nav-text">二、Sequence执行最少的操作</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E4%B8%89%E3%80%81Sequence%E6%98%AF%E6%97%A0%E9%99%90%E7%9A%84"><span class="nav-number">2.3.</span> <span class="nav-text">三、Sequence是无限的</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E5%9B%9B%E3%80%81sequence%E6%AF%8F%E4%B8%80%E6%AD%A5%E4%B8%8D%E4%BA%A7%E7%94%9F%E6%96%B0%E9%9B%86%E5%90%88"><span class="nav-number">2.4.</span> <span class="nav-text">四、sequence每一步不产生新集合</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E4%BA%94%E3%80%81sequence%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E6%B2%A1%E9%82%A3%E4%B9%88%E5%BF%AB%EF%BC%9F"><span class="nav-number">2.5.</span> <span class="nav-text">五、sequence什么时候没那么快？</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E5%85%AD%E3%80%81%E7%9C%8B%E7%9C%8BJava%E7%9A%84Stream%E6%93%8D%E4%BD%9C"><span class="nav-number">2.6.</span> <span class="nav-text">六、看看Java的Stream操作</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E4%B8%83%E3%80%81%E8%B0%83%E8%AF%95Sequence"><span class="nav-number">2.7.</span> <span class="nav-text">七、调试Sequence</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E4%B8%89%E3%80%81%E6%80%BB%E7%BB%93"><span class="nav-number">3.</span> <span class="nav-text">三、总结</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="wangduwei"
      src="/images/avatar.jpeg">
  <p class="site-author-name" itemprop="name">wangduwei</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">11</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/duweiwang" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;duweiwang" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:wangduwei8@gmail.com" title="E-Mail → mailto:wangduwei8@gmail.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">wangduwei</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
      <span class="post-meta-item-text">站点总字数：</span>
    <span title="站点总字数">53k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span class="post-meta-item-text">站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">48 分钟</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/medium-zoom@1/dist/medium-zoom.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  
  <script>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>



  <script>
  if (CONFIG.page.isPost) {
    wpac_init = window.wpac_init || [];
    wpac_init.push({
      widget: 'Rating',
      id    : 31838,
      el    : 'wpac-rating',
      color : 'fc6423'
    });
    (function() {
      if ('WIDGETPACK_LOADED' in window) return;
      WIDGETPACK_LOADED = true;
      var mc = document.createElement('script');
      mc.type = 'text/javascript';
      mc.async = true;
      mc.src = '//embed.widgetpack.com/widget.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(mc, s.nextSibling);
    })();
  }
  </script>












  

  

<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.css">

<script>
NexT.utils.loadComments(document.querySelector('#gitalk-container'), () => {
  NexT.utils.getScript('//cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js', () => {
    var gitalk = new Gitalk({
      clientID    : '16c7d02bc3ca2bae3d85',
      clientSecret: 'bfda6fb671841e71f55e41fdd3fb794c8dbf40b2',
      repo        : 'duweiwang.github.io',
      owner       : 'duweiwang',
      admin       : ['duweiwang'],
      id          : 'a0622951ca3e42763fa60f3e96108dc9',
        language: '',
      distractionFreeMode: true
    });
    gitalk.render('gitalk-container');
  }, window.Gitalk);
});
</script>


<script>
NexT.utils.loadComments(document.querySelector('#valine-comments'), () => {
  NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
    var GUEST = ['nick', 'mail', 'link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item => {
      return GUEST.includes(item);
    });
    new Valine({
      el         : '#valine-comments',
      verify     : false,
      notify     : false,
      appId      : '45lTcsdp8QJNGsmN5wEaOtV5-gzGzoHsz',
      appKey     : 'QsK8vR7pb8w0M1eIk7QE50yF',
      placeholder: "Just go go",
      avatar     : 'mm',
      meta       : guest,
      pageSize   : '10' || 10,
      visitor    : false,
      lang       : '' || 'zh-cn',
      path       : location.pathname,
      recordIP   : false,
      serverURLs : ''
    });
  }, window.Valine);
});
</script>


  <!-- 页面点击小红心 -->
  
        <script type="text/javascript" src="/js/love.js"></script>
  
</body>
</html>
